#-*- Makefile -*-

## Defaults for user settings, see MkRules.dist for descriptions.  Since
## Rtools42, Rtools assumes that the compiler toolchain (e.g.  gcc, as, ...
## for Intel targets) is on PATH
LOCAL_SOFT ?= $(shell which `echo $(CC) | sed -e 's/ .*//g'` | sed -e 's!/bin/[^/]\+!!g')
EXT_LIBS ?= $(LOCAL_SOFT)
G_FLAG ?= $(if $(USE_LLVM),-g3,-gdwarf-2)
USE_ATLAS ?= NO
USE_OPENBLAS ?= NO
ATLAS_PATH ?= 
TOOL_PATH ?=
BINPREF64 ?= 
CCBASE = $(if $(USE_LLVM),clang,gcc)
COMPILED_BY ?= $(CCBASE)-$(shell $(CC) --version | grep -E -o "([0-9]{1,}\.){2,}[0-9]{1,}")
M_ARCH ?=
AS_ARCH ?=
RC_ARCH ?=
DT_ARCH ?=

## only WIN=64 is supported from R 4.2.0 to R 4.3
## from R 4.4.0, WIN= is also supported and means there are no
## subarchitectures (so e.g.  Rgui.exe is directly under bin/) and no
## assumptions are made about the target (it is used with aarch64 builds)
WIN ?= 64

PKG_CONFIG ?= $(BINPREF)pkg-config

USE_PKG_CONFIG ?= 1
ifdef USE_PKG_CONFIG
  ifeq (,$(shell $(PKG_CONFIG) --version 2>/dev/null))
    USE_PKG_CONFIG =
  endif
  ifeq ($(filter-out no NO 0 off OFF,$(USE_PKG_CONFIG)),)
    USE_PKG_CONFIG =
  endif
endif

USE_ICU ?= YES
ICU_PATH ?= 
USE_CAIRO ?= YES
CURL_CA_BUNDLE ?=
USE_LIBCURL = yes
ifndef USE_ICU
  ifeq ($(filter-out no NO,$(USE_ICU)),)
    USE_ICU =
  endif
endif

ifndef USE_PKG_CONFIG
  ICU_LIBS ?= -lsicuin -lsicuuc $(EXT_LIBS)/lib/sicudt.a -lstdc++
  # (dynamic linking) ICU_LIBS ?= -licuin -licuuc -licudt -lstdc++

  CAIRO_CPPFLAGS ?= "-I$(EXT_LIBS)/include/cairo -I$(EXT_LIBS)/include/freetype2 -DCAIRO_WIN32_STATIC_BUILD"
  ## support freetype, curl built with libbrotli and without
  LIBBROTLI = $(or $(and $(wildcard $(EXT_LIBS)/lib/libbrotlidec.a),-lbrotlidec -lbrotlicommon),)
  ## support curl built with libpsl and without
  LIBPSL = $(or $(and $(wildcard $(EXT_LIBS)/lib/libpsl.a),-lpsl),)
  ## support curl built with libnghttp2 and without
  LIBH2 = $(or $(and $(wildcard $(EXT_LIBS)/lib/libnghttp2.a),-lnghttp2),)
  CAIRO_LIBS ?= "-lcairo -lfontconfig -lfreetype -lpng -lpixman-1 -lexpat -lharfbuzz \
                -lbz2 -lintl -lz -liconv -luuid -lstdc++ -lgdi32 -lmsimg32 -lole32 \
                $(LIBBROTLI)"

  CURL_LIBS ?= -lcurl $(LIBH2) $(LIBPSL) -lbcrypt -lzstd -lrtmp -lssl -lssh2 -lbcrypt -lgcrypt \
               -lcrypto -lgdi32 -lz \
               -lws2_32 -lgdi32 -lcrypt32 -lidn2 -lunistring -liconv -lgpg-error -lwldap32 \
               -lwinmm $(LIBBROTLI)
else
  ifndef ICU_LIBS
    # Some builds of ICU provide two data libraries, a small one 
    # with no data (e.g. libsicudt.a) and a large one with the
    # real data (e.g. sicudt.a). We want to link the large one
    # in that case, but pkg-config may return the small one.
    ICU_LIBS = $(patsubst -l%icudt, \
      $(or $(firstword $(wildcard \
        $(EXT_LIBS)/lib/icudt.dll $(EXT_LIBS)/bin/icudt.dll \
        $(EXT_LIBS)/lib/icudt.a $(EXT_LIBS)/bin/icudt.a \
        $(EXT_LIBS)/lib/sicudt.a $(EXT_LIBS)/bin/sicudt.a)), \
      -l%icudt), \
      $(shell $(PKG_CONFIG) --libs icu-i18n))
  endif

  ifdef USE_LLVM
    # work-around for incorrect .pc file
    CAIRO_CPPFLAGS ?= "$(shell $(PKG_CONFIG) --cflags cairo-fc) -I$(EXT_LIBS)/include/freetype2"
  else
    CAIRO_CPPFLAGS ?= "$(shell $(PKG_CONFIG) --cflags cairo-fc)"
  endif

  CAIRO_LIBS ?= "$(shell $(PKG_CONFIG) --libs cairo-fc)"

  CURL_LIBS ?= $(shell $(PKG_CONFIG) --libs libcurl)  
endif

BUILD_HTML ?= NO
MIKTEX ?= TRUE
TEXI2ANY ?= texi2any
TEXI2DVI = env COMSPEC= texi2dvi
MAKEINFO = texi2any
EOPTS ?= $(if $(USE_LLVM),,-mfpmath=sse -msse2 -mstackrealign)
SANOPTS ?=
CSTD ?= -std=gnu2x
OPENMP ?= -fopenmp
PTHREAD ?= -pthread
ISDIR ?= C:/Program Files (x86)/Inno Setup 6
QPDF ?=
DLLs64 ?=
WIX3DIR ?=
WIX_PERSONAL ?= 0

## =============== end of user setting defaults  ===================

NM_FILTER ?= | $(SED) -e '/[.]refptr[.]/d' -e '/[.]weak[.]/d'

ifeq "$(WIN)" "64"
  R_ARCH = /x64
  arch_DEFS = -DR_ARCH='"x64"'
  BINPREF = $(BINPREF64)
  SYMPAT = 's/^.* [BCDRT] / /p'
else
  R_ARCH = 
  arch_DEFS = -DR_ARCH='""'
  BINPREF = $(BINPREF64)
  SYMPAT = 's/^.* [BCDRT] / /p'
endif

BINDIR=bin$(R_ARCH)

ifdef USE_IMPLIBS
IMPDIR=lib
else
IMPDIR=$(BINDIR)
endif

LLVMPREF=
ifdef USE_LLVM
  # only set when BINPREF is empty or ends by /
  #   to support e.g. BINPREF=aarch64-w64-mingw32.static.posix-
  ifeq ($(patsubst %/,,$(lastword $(BINPREF))),)
    LLVMPREF="llvm-"
  endif
endif

AR = $(BINPREF)$(LLVMPREF)ar
CAT=cat
CC=$(BINPREF)$(CCBASE) $(M_ARCH)

CP=cp
# as set by make
CPP=$(CC) -E
DLL=$(CC) $(SANOPTS)
DLLTOOL=$(BINPREF)$(LLVMPREF)dlltool
## some versions have trouble with paths, so we always need this
## even for native builds
DLLTOOLFLAGS=--as $(BINPREF)$(LLVMPREF)as $(DT_ARCH) -k
ECHO=echo
ifndef USE_LLVM
  FC=$(BINPREF)gfortran $(M_ARCH)
  FLIBS=-lgfortran -lquadmath
else
  FC=$(BINPREF)flang $(M_ARCH)
  ## Fortran_main is needed/available only in some builds of llvm/flang-new
  LIBFM = $(or $(and $(wildcard $(EXT_LIBS)/lib/libFortran_main.a),-lFortran_main),)
  FLIBS=-lFortranRuntime -lFortranDecimal $(LIBFM) -lc++ -lm
endif
LINKER=$(MAIN_LD)
MAIN_LD=$(CC)
## MAKEINFO = $(TEXI2ANY)
MKDIR=mkdir
NM=$(BINPREF)$(LLVMPREF)nm
RANLIB = $(BINPREF)$(LLVMPREF)ranlib
RESCOMP=$(BINPREF)$(LLVMPREF)windres $(RC_ARCH)
SHLIB_LD=$(CC)
SHLIB_LDFLAGS=-shared

## If the Fortran compiler is gfortran >= 7, R used to add
## -fno-optimize-sibling-calls to avoid recent gfortran optimizations
## that break with LAPACK/BLAS-style passing of length-1 strings
## (without hidden arguments giving their lengths).
##
## One could also use -ftail-call-workaround=2, which would be less
## restrictive, and has been added after the breakages were discovered.
## However, it is documented that this option may be removed in the future.
## https://gcc.gnu.org/bugzilla/show_bug.cgi?id=90329
##
## -fno-optimize-sibling-calls is no longer forced once all packages are
## passing char lengths.

## GF7OPTS =
## GFVER = $(shell echo "__GNUC__" | $(FC) -E -P -)
## ifneq ($(GFVER),"")
## GF7OPTS = $(shell [ $(GFVER) -ge 7 ] && echo "-fno-optimize-sibling-calls")
## endif

ifneq "$(LTO)" ""
  ifndef USE_LLVM
    AR = $(BINPREF)gcc-ar
    NM = $(BINPREF)gcc-nm
    RANLIB = $(BINPREF)gcc-ranlib
  endif
  DLLFLAGS += $(CFLAGS)
endif

# as set by make
RM=rm -f
SED=sed
SORT=sort

.SUFFIXES:
.SUFFIXES: .c .cc .cpp .C .f .o .a .def .exp .dll .exe .d .f90 .f95 .m .S

.c.d:
	@echo "making $@ from $<"
	@$(CC) -MM $(CPPFLAGS) $($*-CPPFLAGS) $(DEFINES) $< -o $@

.c.o:
	$(CC) $(CPPFLAGS) $($*-CPPFLAGS) $(CFLAGS) $($*-CFLAGS) $(DEFINES) -c $< -o $@

.f.o:
	$(FC) $(FFLAGS) $($*-FFLAGS) -c $< -o $@

## used in src/extra/blas
.f90.o:
	$(FC) $(FFLAGS) $($*-FFLAGS) -c $< -o $@

## $($*-LINKFLAGS) is used for Rgui Rterm and Rscript
%.exe:
	$(LINKER) $(LINKFLAGS) $($*-LINKFLAGS) $(SANOPTS) -o $@ $^ $($*-LIBS) $(LIBS)

## It does little sense to have $($*-DLLFLAGS) here (and not in etc/Makeconf)
## $($*-DLLLIBS) is used for R and lapack
%.dll:
	@$(ECHO) EXPORTS > $*.def
	@$(NM) $^ | $(SED) -n $(SYMPAT) $(NM_FILTER) >> $*.def
	$(DLL) -shared $(DLLFLAGS) $($*-DLLFLAGS) -o $@ $*.def $^ $($*-DLLLIBS) $(DLLLIBS)
	@$(RM) $*.def

## It does no sense to have $($*-DLLTOOLFLAGS) here, and it is unused.
lib%.dll.a: %.def
	$(DLLTOOL) $(DLLTOOLFLAGS) $($*-DLLTOOLFLAGS) --dllname $*.dll --input-def $*.def --output-lib $@

%.a:
#	@$(ECHO) -------- Building $@ from $^ --------
	@$(RM) $@
	$(AR) crs $@ $^

%.o: %.rc
	$(RESCOMP) $(RESFLAGS) $($*-RESFLAGS) -i $< -o $@
